﻿using System;
using DepIC.Attributes;

namespace DepIC
{
    /// <summary>Readonly DI container</summary>
    public interface IReadOnlyContainer : IDisposable
    {
        /// <summary>Returns an instance of registered <see cref="TKey"/> type from DI container</summary>
        /// <exception cref="ContainerException">If <see cref="TKey"/> type is not registered</exception>
        TKey Get<TKey>();

        /// <summary>Returns an instance of registered <see cref="keyType"/> type from DI container</summary>
        /// <exception cref="ArgumentNullException">If <see cref="keyType"/> is null</exception>
        /// <exception cref="ContainerException">If <see cref="keyType"/> type is not registered</exception> 
        object Get(Type keyType);

        /// <summary>Checks whether <see cref="TKey"/> is registered in DI container</summary>
        bool Contains<TKey>();

        /// <summary>Checks whether <see cref="keyType"/> is registered in DI container</summary>
        /// <exception cref="ArgumentNullException">If <see cref="keyType"/> is null</exception>
        bool Contains(Type keyType);

        /// <summary>Create an instance of <see cref="T"/> type and injects register in DI container types</summary>
        /// <exception cref="ContainerException">If there is no default constructor or constructor marked with <see cref="InjectAttribute"/> attribute</exception>
        /// <exception cref="ContainerException">If injected type is not registered in DI container</exception>
        T CreateInstance<T>();

        /// <summary>Create an instance of <see cref="type"/> type and injects register in DI container types</summary>
        /// <exception cref="ArgumentNullException">If <see cref="type"/> is null</exception> 
        /// <exception cref="ContainerException">If there is no default constructor or constructor marked with <see cref="InjectAttribute"/></exception>
        /// <exception cref="ContainerException">If injected type is not registered in DI container</exception>
        object CreateInstance(Type type);

        /// <summary>The root which is used for syncronization of threads</summary>
        object SyncRoot { get; }
    }
}
